package org.bjf.modules.user.web.controller.api;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.jsonwebtoken.Claims;
import lombok.Data;
import lombok.experimental.Accessors;
import org.bjf.exception.CommMsgCode;
import org.bjf.modules.user.bean.User;
import org.bjf.modules.user.enums.UserRedisKey;
import org.bjf.utils.ExceptionAssert;
import org.bjf.utils.RedisUtil;
import org.bjf.utils.TokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * jwt 登录demo示例
 * <p>
 * jwt使用场景: 1. 一次性验证,如邮件激活帐户 2. restful api的无状态认证，客户端和服务端共享 secret，spring security oauth jwt
 */
@RestController
public class JwtLoginController {

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 登录
     */
    @RequestMapping("jwt/login")
    public LoginResp login(String phone, String password) {

        // 模拟登录成功取到用户信息
        User user = new User();
        user.setUserId(555L);
        user.setUsername("zhangsan");

        return createLoginResp(user.getUserId(), user.getUsername());
    }

    /**
     * 刷新access_token
     */
    @RequestMapping("app/refresh-token")
    public LoginResp refreshToken(@RequestParam("refresh_token") String refreshToken) {
        //=== 1.校验refreshToken，取出userId
        Claims claims = TokenUtil.parseJwtToken(refreshToken);
        Long userId = (Long) claims.get("userId");
        String loginName = claims.getSubject();

        //=== 2.检查refreshToken是否黑名单
        boolean exists = redisUtil.hasKey(UserRedisKey.INVALID_REFRESH_TOKEN.as(refreshToken));
        ExceptionAssert.isTrue(exists, CommMsgCode.UNAUTHORIZED, "refreshToken 已经失效");

        //=== 3.生成的token信息，且把旧的refreshToken放入黑名单
        LoginResp loginResp = createLoginResp(userId, loginName);
        redisUtil.setObj(UserRedisKey.INVALID_REFRESH_TOKEN.as(refreshToken), refreshToken, 86400 * 100);

        return loginResp;
    }

    /**
     * 创建登录成功信息
     */
    private LoginResp createLoginResp(long userId, String loginName) {
        // 1小时
        String accessToken = TokenUtil.genJwtToken(userId, loginName, 3600);
        // 15天
        String newRefreshToken = TokenUtil.genJwtToken(userId, loginName, 86400 * 15);

        LoginResp loginResp = new LoginResp();
        loginResp.setAccessToken(accessToken);
        loginResp.setRefreshToken(newRefreshToken);
        loginResp.setExpiresIn(3600);
        return loginResp;
    }

    @Data
    @Accessors(chain = true)
    public static class LoginResp {

        @JsonProperty("access_token")
        private String accessToken;
        @JsonProperty("refresh_token")
        private String refreshToken;
        @JsonProperty("expires_in")
        private long expiresIn;

    }


}
